package com.finance.system.nio;


import lombok.Data;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

@Data
public class SocketChannelBufferedWrapper {
    private SocketChannel sc;
    private Boolean cached = Boolean.FALSE;
    private Integer bodyLength = -1;
    private final Integer DEFAULT_READ_BUFFER_LENGTH = 100;
    private final Integer DEFAULT_HEAD_LENGTH = 4;
    private ByteBuffer headBuffer ;
    private ByteBuffer bodyCacheBuffer;
    private ByteBuffer readBuffer;

    public SocketChannelBufferedWrapper(Integer headByteNum,Integer maxBodyLength){
        this.headBuffer = ByteBuffer.allocate(headByteNum);
        this.bodyCacheBuffer = ByteBuffer.allocate(maxBodyLength);
    }

    public SocketChannelBufferedWrapper wrapper(SocketChannel sc){
        this.sc = sc;
        return this;
    }

    /**
     * 准备去读，初始化一个空的读缓冲区
     * @return
     */
    public SocketChannelBufferedWrapper prepareRead(){
        if(this.readBuffer == null){
            this.readBuffer = ByteBuffer.allocate(DEFAULT_READ_BUFFER_LENGTH);
        }else{
            this.readBuffer.clear();
        }
        return this;
    }

    /**
     * 将从内核读取字节到 读缓冲区
     * @return
     * @throws IOException
     */
    public SocketChannelBufferedWrapper read() throws IOException{
        this.sc.read(readBuffer);
        return this;
    }

    /**
     * 写之前做准备，将读到的字节缓冲区反转
     * @return
     */
    public SocketChannelBufferedWrapper prepareWrite(){
        this.readBuffer.flip();
        return this;
    }

    /**
     * 缓存进消息体缓存区中
     * @return
     */
    public SocketChannelBufferedWrapper cacheToBodyBuffer(){
        this.bodyCacheBuffer.put(readBuffer);
        return this;
    }

    /**
     * 从读到的字节数组中缓存 剩余消息长度的字节
     * @return
     */
    public SocketChannelBufferedWrapper cacheLeftLengthByteToBodyBuffer(){
        bodyCacheBuffer.put(
                ByteBufferUtils.readBytes(readBuffer, bodyLength - bodyCacheBuffer.position())
        );
        return this;
    }

    /**
     * 从读到的字节数组中缓存 剩余头部长度的字节
     * @return
     */
    public SocketChannelBufferedWrapper cacheLeftLengthByteToHeadBuffer(){
        headBuffer.put(
                ByteBufferUtils.readBytes(readBuffer, DEFAULT_HEAD_LENGTH - headBuffer.position())
        );
        if(headBuffer.position() == DEFAULT_HEAD_LENGTH){
            headBuffer.flip();
            bodyLength = ByteBufferUtils.byteArrayToInt(ByteBufferUtils.readBytes(headBuffer));
        }
        return this;
    }

    /**
     * 检查是否需要缓存所有 @link{readBuffer}剩余的
     *
     * 如果发现已经缓存的长度 加上 剩余长度 不足于 总长度，则认为需要缓存
     * @return
     */
    public Boolean checkNeedCacheReadBufferRemaining(){
        return bodyCacheBuffer.position() + readBuffer.remaining() <= bodyLength;
    }

    /**
     * 检查缓存已经足够（完成）
     * @return
     */
    public Boolean checkIfCacheCompleted(){
        return bodyCacheBuffer.position()== bodyLength;
    }


    /**
     *  缓冲标识复位&缓冲内存复位&bodyLength复位
     * @return
     */
    public SocketChannelBufferedWrapper resetFlagAndCache(){
        this.cached = Boolean.FALSE;
        this.bodyLength = -1;
        this.bodyCacheBuffer.clear();
        this.headBuffer.clear();
        return this;
    }


    /**
     * 检查剩余字节足够填满消息头
     * @return
     */
    public Boolean checkRemainingEnoughToHead(){
        return headBuffer.position() + readBuffer.remaining() >= DEFAULT_HEAD_LENGTH;
    }

    /**
     * 输出消息体
     */
    public void printBody(){
        bodyCacheBuffer.flip();
        byte[] bytes = ByteBufferUtils.readBytes(bodyCacheBuffer);
        String bodyStr = new String(bytes);
        System.out.println("server read："+bodyStr);
    }


}
